﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  JoinNowActivityBase.cs
//    
// Abstract:
//
//  Abstract base class that describes most of the behavior for
//  both instant message and voice versions of Join Now.
//  
//--

using System;
using System.Collections.Generic;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using Microsoft.OfficeCommunicationsServer.Applications.Common;
using Microsoft.Rtc.Workflow.Activities;
using Microsoft.Rtc.Collaboration;

namespace Microsoft.EnhancedReminders.Dispatcher.Workflow
{
    /// <summary>
    /// Abstract base class for join now workflow activities.
    /// </summary>
    public abstract class JoinNowActivityBase : Activity, IInstanceDependencyContainer, IEventActivity, IActivityEventListener<QueueEventArgs>
	{
        #region Fields

        private string _queueName;

        #endregion Fields

        /// <summary>
        /// The call to be transferred.
        /// </summary>
        public abstract Call Call
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the NotificationItem pertaining to this conference.
        /// </summary>
        public abstract CalendarNotificationItem Notification
        {
            get;
            set;
        }

        /// <summary>
        /// Begins the asynchronous operation to join the conference, and then waits for the
        /// async operations to complete before returning so that we close the activty on the
        /// correct thread.
        /// </summary>
        protected sealed override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            Logger.WriteTraceInformation(Notification.Context, "Executing JoinNowInstantMessageActivity");
            _queueName = new Guid().ToString();

            if (this.ProcessQueueItem(executionContext))
            {
                return ActivityExecutionStatus.Closed;
            }

            Subscribe(executionContext, this);
            return ActivityExecutionStatus.Executing;
        }

        /// <summary>
        /// Process an item on the workflow queue.
        /// </summary>
        private bool ProcessQueueItem(ActivityExecutionContext context)
        {
            WorkflowQueuingService queuingService = context.GetService<WorkflowQueuingService>();

            if (!queuingService.Exists(QueueName))
            {
                return false;
            }

            WorkflowQueue queue = queuingService.GetWorkflowQueue(QueueName);

            if (queue.Count == 0)
            {
                return false;
            }

            // just dequeue the item from the queue; we don't check for any specific result.
            queue.Dequeue();
            Unsubscribe(context, this);

            return true;
        }

        #region IInstanceDependencyContainer Members

        Dictionary<string, object> _instanceDependencyProperties = new Dictionary<string, object>();

        /// <summary>
        /// Returns the collection of InstanceDependencyProperties
        /// </summary>
        public System.Collections.Generic.Dictionary<string, object> InstanceDependencyProperties
        {
            get
            {
                return _instanceDependencyProperties;
            }
        }

        #endregion

        #region IEventActivity Members
        /// <summary>
        /// Returns the name of the queue to use for queuing asynchronous events for
        /// the JoinNowInstantMessageActivity.
        /// </summary>
        public IComparable QueueName
        {
            get
            {
                return _queueName;
            }
        }

        /// <summary>
        /// Creates the queue and registers for the join now operation.
        /// </summary>
        public void Subscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
        {
            WorkflowQueuingService queuingService = parentContext.GetService<WorkflowQueuingService>();

            if (queuingService != null && !queuingService.Exists(QueueName))
            {
                WorkflowQueue queue = queuingService.CreateWorkflowQueue(QueueName, false);
                queue.RegisterForQueueItemAvailable(parentEventHandler, QualifiedName);
            }

            SubscribeToJoinNowService(parentContext);
        }

        /// <summary>
        /// Removes the join now operation from the queue and deletes the queue.
        /// </summary>
        public void Unsubscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
        {
            WorkflowQueuingService queuingService = parentContext.GetService<WorkflowQueuingService>();

            if (queuingService != null)
            {
                WorkflowQueue queue = queuingService.GetWorkflowQueue(QueueName);

                if (queue != null)
                {
                    queue.UnregisterForQueueItemAvailable(parentEventHandler);
                    queuingService.DeleteWorkflowQueue(QueueName);
                }
            }

            UnsubscribeFromJoinNowService(parentContext);
        }

        #endregion

        /// <summary>
        /// Subscribes a concrete Join Now Activity to its respective service class.
        /// </summary>
        protected abstract void SubscribeToJoinNowService(ActivityExecutionContext parentContext);
        
        /// <summary>
        /// Unsubscribes a concrete Join Now Activity from its respective service class.
        /// </summary>
        protected abstract void UnsubscribeFromJoinNowService(ActivityExecutionContext parentContext);

        #region IActivityEventListener<QueueEventArgs> Members

        /// <summary>
        /// Called when an item is available on the WorkflowQueue for this WorkflowInstance.
        /// </summary>
        public void OnEvent(object sender, QueueEventArgs e)
        {
            if (ExecutionStatus == ActivityExecutionStatus.Executing)
            {
                ActivityExecutionContext executionContext = sender as ActivityExecutionContext;

                if (ProcessQueueItem(executionContext))
                {
                    executionContext.CloseActivity();
                }
            }
        }

        #endregion
	}
}
